package 多线程;

import java.util.concurrent.Semaphore;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 我们提供一个类：

 class FooBar {
 public void foo() {
     for (int i = 0; i < n; i++) {
       print("foo");
     }
 }

 public void bar() {
     for (int i = 0; i < n; i++) {
       print("bar");
     }
 }
 }
 两个不同的线程将会共用一个 FooBar 实例。其中一个线程将会调用 foo() 方法，另一个线程将会调用 bar() 方法。

 请设计修改程序，以确保 "foobar" 被输出 n 次。

  

 示例 1:

 输入: n = 1
 输出: "foobar"
 解释: 这里有两个线程被异步启动。其中一个调用 foo() 方法, 另一个调用 bar() 方法，"foobar" 将被输出一次。
 示例 2:

 输入: n = 2
 输出: "foobarfoobar"
 解释: "foobar" 将被输出两次。
 */

public class _1115交替打印FooBar {
    private int n;
    // 使用信号量
    private Semaphore s1 = new Semaphore(1);
    private Semaphore s2 = new Semaphore(0);

    // 使用 lock
    private Lock lock = new ReentrantLock();
    private int state = 1;
    private Condition c1 =  lock.newCondition();
    private Condition c2 =  lock.newCondition();

    public _1115交替打印FooBar(int n) {
        this.n = n;
    }


    // 方法一: 使用信号量
    public void foo(Runnable printFoo) throws InterruptedException {

        for (int i = 0; i < n; i++) {
            s1.acquire();
            // printFoo.run() outputs "foo". Do not change or remove this line.
            printFoo.run();
            s2.release();
        }
    }

    public void bar(Runnable printBar) throws InterruptedException {

        for (int i = 0; i < n; i++) {
            lock.lock();
            s2.acquire();
            // printBar.run() outputs "bar". Do not change or remove this line.
            printBar.run();
            s1.release();
            lock.unlock();
        }
    }


    // 方法二 使用 Lock
    public void foo2(Runnable printFoo) throws InterruptedException {

        for (int i = 0; i < n; i++) {
            lock.lock();
            while ( state != 1){
                c1.await();
            }
            // printFoo.run() outputs "foo". Do not change or remove this line.
            printFoo.run();
            state = 2 ; // 更换标志位
            c2.signal(); //释放 c2
            lock.unlock();
        }
    }

    public void bar2(Runnable printBar) throws InterruptedException {

        for (int i = 0; i < n; i++) {
            lock.lock();
            while ( state !=2 ){
                c2.await();
            }
            // printBar.run() outputs "bar". Do not change or remove this line.
            printBar.run();
            state =1;
            c1.signal(); //释放c1
            lock.unlock();
        }
    }

}
